package com.bootx.predict;

import com.bootx.predict.pojo.PredictPlugin;
import com.bootx.predict.pojo.PredictionResult;
import com.bootx.predict.pojo.RedPacketBatch;
import com.bootx.predict.pojo.RedPacketRecord;
import com.bootx.predict.util.PredictUtils;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author black
 * 马尔可夫链策略
 */
@Component("markovChainStrategy")
public class MarkovChainPredict extends PredictPlugin {
    @Override
    public String getName() {
        return "markovChainStrategy";
    }

    @Override
    public List<PredictionResult> predict(List<RedPacketBatch> list, Set<Integer> indexes) {
        List<RedPacketRecord> history = PredictUtils.parseData(list);
        // 按 index 分组
        Map<Integer, List<Boolean>> stateMap = new HashMap<>();
        for (RedPacketRecord r : history) {
            stateMap.computeIfAbsent(r.getIndex(), k -> new ArrayList<>())
                    .add(PredictUtils.isAmountOdd(r.getAmount()));
        }

        List<PredictionResult> results = new ArrayList<>();
        for (int idx : indexes) {
            List<Boolean> states = stateMap.getOrDefault(idx, Collections.emptyList());
            int total = states.size();
            int oddCount = (int) states.stream().filter(b -> b).count();

            double avgOpenTime = history.stream()
                    .filter(r -> r.getIndex() == idx)
                    .mapToInt(RedPacketRecord::getOpenTime)
                    .average().orElse(0);

            // 如果历史不足 2 条，返回 0.5
            if (states.size() < 2) {
                results.add(new PredictionResult(idx, total, oddCount, 0.5, Double.valueOf(avgOpenTime+"").intValue()));
                continue;
            }

            // 统计转移次数
            int OO = 0, OE = 0, EO = 0, EE = 0;
            for (int i = 1; i < states.size(); i++) {
                boolean prev = states.get(i - 1);
                boolean curr = states.get(i);
                if (prev && curr) {
                    OO++;
                } else if (prev && !curr) {
                    OE++;
                } else if (!prev && curr) {
                    EO++;
                } else {
                    EE++;
                }
            }

            // 转移概率
            double pOO = (OO + 1.0) / (OO + OE + 2);
            double pOE = (OE + 1.0) / (OO + OE + 2);
            double pEO = (EO + 1.0) / (EO + EE + 2);
            double pEE = (EE + 1.0) / (EO + EE + 2);
            boolean lastState = states.get(states.size() - 1);
            double nextOddProb = lastState ? pOO : pEO;

            results.add(new PredictionResult(idx, total, oddCount, nextOddProb, Double.valueOf(avgOpenTime+"").intValue()));
        }



        return results;
    }
}
